import { DataRegister } from './../../domain/models/dataRegister';
import { DepartmentService } from './../../service/departmentService';
import { DataRegisterService } from './../../service/dataRegisterService';
import { RouteOptionsBase } from './../../common/http/router/routeDecorators';
import { DataSourceService } from './../../service/dataSourceService';
import { ServiceManager } from './../../common/serviceFactory/serviceManager';
import { DataSource } from './../../domain/models/dataSource';
import * as Koa from 'koa';
import { Guid, route, RouteOptionsVerify, UsingLock } from "../../common";
import { ServiceException } from '../../common/excpetion';
import { Transaction } from 'tiny-entity2';
import { ApiDataContext } from '../../domain/apiDataContext';
import xlsx from 'node-xlsx';
import { DataChangeLogService } from '../../service/dataChangeLogService';
import moment = require('moment');
import { DataChangeLogStatus } from '../../domain/models/dataChangeLog';
import { UserService } from '../../service/userService';
import { AccountService } from '../../service/accountService';

const dSvr = ServiceManager.Current.GetService<DataSourceService>('DataSourceService');
const rSvr = ServiceManager.Current.GetService<DataRegisterService>('DataRegisterService');
const departmentSvr = ServiceManager.Current.GetService<DepartmentService>('DepartmentService');
const dataSvr = ServiceManager.Current.GetService<DataChangeLogService>('DataChangeLogService');
const userSvr = ServiceManager.Current.GetService<UserService>('UserService');
const accSvr = ServiceManager.Current.GetService<AccountService>('AccountService');

class DataSourceController {
    @route(new RouteOptionsVerify('GET', '/api/dataSource'))
    async queryDataSources(ctx: Koa.Context, next) {
        let p = ctx.query;
        ctx.response.body = await dSvr.QueryDataSource(p);
        await next();
    }
    @route(new RouteOptionsBase('GET', '/api/dataSource/:id'))
    async getDataSourceInfoById(ctx: Koa.Context, next) {
        let { id } = ctx.params;
        ctx.response.body = await dSvr.GetDataSourceById(id);
        await next();
    }
    @route(new RouteOptionsVerify('post', '/api/dataSource'))
    async createDataSource(ctx: Koa.Context, next) {
        let data: DataSource = ctx.request.body;
        if (!data.dataType) {
            throw new ServiceException('未填写dataType');
        }
        if (!data.data) {
            throw new ServiceException('未填写data');
        }

        await UsingLock(data.id, async () => {
            data = await dSvr.CreateDataSource(data);
        });

        ctx.response.body = data;

        await next();
    }
    @route(new RouteOptionsVerify('PUT', '/api/dataSource'))
    async updateDataSource(ctx: Koa.Context, next) {
        let data: DataSource = ctx.request.body;
        ctx.response.body = await dSvr.UpdateDataSource(data);
        await next();
    }
    @route(new RouteOptionsVerify('DELETE', '/api/dataSource/:id'))
    async deleteDataSource(ctx: Koa.Context, next) {
        let { id } = ctx.params;
        await UsingLock(id, async () => {
            return dSvr.DeleteDataSourceById(id);
        });
        ctx.response.body = {};
        await next();
    }

    @route(new RouteOptionsVerify('Get', '/api/data'))
    async queryDataSourceDatas(ctx: Koa.Context, next) {
        let userId = ctx.headers['userid'];
        let orgId = ctx.headers['orgid'];

        let p: {
            dataType?: string
            userId?: string;
        } = ctx.query;

        p.userId = userId;

        if (!p.dataType) {
            throw new ServiceException('未传入dataType');
        }

        ctx.response.body = await queryDataRegisterData(p, orgId);

        await next();
    }

    @route(new RouteOptionsBase('POST', '/api/data/export'))
    async exportData(ctx: Koa.Context, next) {
        let userId = ctx.headers['userid'];
        let orgId = ctx.headers['orgid'];

        let tableHeaders: {
            name: string;
            bindField: string;
        }[] = ctx.request.body;

        let p: {
            dataType?: string
            userId?: string;
            pageIndex?: number;
            countOfPage?: number;
        } = ctx.query;

        p.userId = userId;

        if (!p.dataType) {
            throw new ServiceException('未传入dataType');
        }

        delete p.pageIndex;
        delete p.countOfPage;

        let result = await queryDataRegisterData(p, orgId);

        let row = [];


        result.list.forEach(item => {
            let rowData = [];
            for (let headItem of tableHeaders) {
                rowData.push(item[headItem.bindField]);
            }

            row.push(rowData);
        });

        row.unshift(tableHeaders.map(x => x.name));

        let buffer: Buffer = xlsx.build([{ name: 'sheet1', data: row }]);

        ctx.set('Content-type', 'application/vnd.openxmlformats');
        ctx.set('Content-disposition', 'attachment;filename=tableExport.xlsx');

        ctx.response.body = buffer;

        await next();
    }

    @route(new RouteOptionsVerify('POST', '/api/dataSource/assemble'))
    async saveAssembleDataSource(ctx: Koa.Context, next) {
        let data: {
            assemble: any[];
            dataSource: DataSource
        } = ctx.request.body;

        await UsingLock(data.dataSource.objectId, async () => {
            return await Transaction(new ApiDataContext(), async ctx => {
                let ds = await dSvr.GetDataSourceByObjectId(data.dataSource.objectId);
                if (ds) {
                    ds.data = data.dataSource.data;
                    await dSvr.UpdateDataSource(ds, ctx);
                }
                else {
                    await dSvr.CreateDataSource(data.dataSource, ctx);
                }

                await rSvr.DeleteDataRegisterByObjectId(data.dataSource.objectId, ctx);

                for (const item of data.assemble) {
                    let ds = new DataRegister();
                    ds.id = Guid.GetGuid();
                    ds.objectId = data.dataSource.objectId;
                    ds.objectType = data.dataSource.objectType;
                    ds.dataType = data.dataSource.dataType;
                    ds.createTime = Date.now();
                    ds.updateTime = Date.now();
                    ds.data = {
                        fields: item
                    };

                    await rSvr.CreateDataRegister(ds, ctx);
                }
            });
        });

        ctx.response.body = {};

        await next();
    }
}

const queryDataRegisterData = async (p: {
    dataType?: string
    userId?: string;
    orgId?: string;
    dataRegisterId?: string;
    flowNodeId?: string;
}, orgId: string) => {
    let responseData: {
        total: number;
        list: any[]
    }

    // 判断是否是超级用户
    let isSupermite = false;
    if (p.userId) {
        const user = await userSvr.GetUserById(p.userId);
        const account = await accSvr.GetAccountById(user.accountId);
        isSupermite = account.superPermits ? true : false;
    }


    if (p.dataType == 'department') {
        let result = await departmentSvr.QueryDepartment({
            organizationId: orgId
        });

        responseData = result;
    }
    else if (p.dataType == 'user') {
        let result = await userSvr.QueryUser({
            organizationId: orgId
        });
        responseData = result;
    }
    else if (p.dataType == 'dataChangeLog') {
        let result = await dataSvr.QueryDataChangeLog(p as any);

        result.forEach(item => {
            item.createTime = moment(item.createTime).format('YYYY-MM-DD HH:mm') as any;
            item.updateTime = moment(item.updateTime).format('YYYY-MM-DD HH:mm') as any;
            if (item.status == DataChangeLogStatus.Pass) {
                item.status = '已生效';
            }
            else if (item.status == DataChangeLogStatus.InReview) {
                item.status = '审核中';
            }
            else if (item.status == DataChangeLogStatus.UnPass) {
                item.status = '未通过';
            }
        });

        responseData = {
            total: result.length,
            list: result
        };
    }
    else if (p.dataType == 'workflowOrder') {
        p.orgId = orgId;
        if (isSupermite) {
            p.userId = "";
        }
        delete p.flowNodeId;
        let r = await rSvr.QueryDataRegister(p);
        let result = [];
        for (let item of r.list) {
            const obj = JSON.parse(item.data);
            let listItem: any = {
                ...obj.fields
            };
            listItem.id = item.id;
            listItem.objectId = item.objectId;
            listItem.objectType = item.objectType;
            listItem.flowNodesItems = obj.flowNodesItems;
            listItem.workflowId = obj.workflowId;
            listItem.status = item.status;
            if (listItem.flowNodesItems) {
                listItem.curNodeNames = listItem.flowNodesItems.filter(x => x.status == 'process').map(x => x.nodeName).join(',');
            }

            result.push(listItem);
        }

        responseData = {
            total: r.total,
            list: result
        };
    }
    else {
        delete p.dataRegisterId;
        delete p.flowNodeId;
        let r = await rSvr.QueryDataRegister(p);
        let result = [];
        for (let item of r.list) {
            const obj = JSON.parse(item.data);
            let listItem: any = {
                ...obj.fields,
                id: item.id
            };

            result.push(listItem);
        }

        responseData = {
            total: r.total,
            list: result
        };
    }

    return responseData;
}